package org.anderground.editor;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.Charset;

import javax.swing.JFrame;

import org.anderground.core.Logger;
import org.anderground.core.drawer.MetroDrawer;
import org.anderground.core.storage.ModelWriter;
import org.anderground.editor.console.ArgMatcher;
import org.anderground.editor.console.EditorConsole;
import org.anderground.editor.gui.MainWindow;
import org.anderground.editor.gui.view.android.DrawersRegistry;
import org.anderground.editor.storage.ReadersRegistry;
import org.anderground.editor.storage.WritersRegistry;
import org.anderground.editor.tools.ToolsRegistry;
import org.anderground.modules.drawer.dynamic.DynamicDrawer;
import org.anderground.modules.editor.importers.ModelImporter;
import org.anderground.modules.editor.tools.EditorTool;

/**
 * @author Ilya Shurigyn
 * @author Eldar Abusalimov
 */
public class AndergroundEditor {

	public static void main(String args[]) {

		String currentDir = getCurrentDir();
		Logger.i("Application starts from: " + currentDir);
		try {
			WritersRegistry.addSaver("AndroidMetro map(*.xml)", "xml",
					ModelWriter.class);

			// TODO uncomment before release
			String modulesDir = "modules";// currentDir + "modules";

			File file = new File(modulesDir);
			Logger.i("trying to load modules from " + file.getAbsolutePath());
			new DrawerListener().onSuitableClassFound(DynamicDrawer.class);
			ClassReader.loadClasses(file, new DrawerListener(),
					new ReaderListener(), new ToolsListener());

			EditorConsole.processArgs(args);
			if (showFrame(args)) {
				JFrame mainWindow = new MainWindow();
				mainWindow.setVisible(true);
			}
		} finally {
			// TODO save log to file
		}
	}

	/**
	 * check args and run in console if it's necessary
	 * 
	 * @return true if app shuold be runned in console;
	 */
	private static boolean showFrame(String args[]) {

		ArgMatcher matcher = new ArgMatcher(args);
		if ((matcher.haveArg("c") || matcher.haveArg("console")))
			return false;

		return true;
	}

	private static class DrawerListener implements
			ClassReader.OnSuitableClassFoundCallback<MetroDrawer> {

		@Override
		public void onSuitableClassFound(Class<? extends MetroDrawer> cls) {
			try {
				MetroDrawer drawer = (MetroDrawer) cls.newInstance();
				DrawersRegistry.registerDrawer(drawer.getClass(), drawer
						.getName());
			} catch (InstantiationException e) {
				Logger.w("ignoring " + cls.getName());
			} catch (Throwable e) {
				Logger
						.e("failed to load drawer from class " + cls.getName(),
								e);
			}
		}

		@Override
		public Class<MetroDrawer> getSuitableClass() {
			return MetroDrawer.class;

		}

	}

	private static class ReaderListener implements
			ClassReader.OnSuitableClassFoundCallback<ModelImporter> {

		@Override
		public void onSuitableClassFound(Class<? extends ModelImporter> cls) {
			try {
				ModelImporter importer = (ModelImporter) cls.newInstance();
				ReadersRegistry.registerFormat(importer.getClass(), importer
						.getSupportedExtensions(), importer
						.getFormatDescription());
			} catch (InstantiationException e) {
				Logger.w("can't instantiate " + cls.getName());
			} catch (Throwable e) {
				Logger
						.e("failed to load reader from class " + cls.getName(),
								e);
			}
		}

		@Override
		public Class<ModelImporter> getSuitableClass() {
			return ModelImporter.class;
		}

	}

	@SuppressWarnings("unused")
	private static class ToolsListener implements
			ClassReader.OnSuitableClassFoundCallback<EditorTool> {

		@Override
		public void onSuitableClassFound(Class<? extends EditorTool> cls) {
			try {
				Object o = cls.newInstance();
				ToolsRegistry.registerTool(cls);
			} catch (InstantiationException e) {
				Logger.w("ignoring " + cls.getName());
			} catch (Throwable e) {
				Logger.e("failed to load tool from class " + cls.getName(), e);
			}

		}

		@Override
		public Class<EditorTool> getSuitableClass() {
			return EditorTool.class;
		}

	}

	/**
	 * get location of {@link AndergroundEditor} class
	 * 
	 * @return
	 */
	private static String getCurrentDir() {
		String classLocation = null;
		URL location = AndergroundEditor.class.getProtectionDomain()
				.getCodeSource().getLocation();
		try {
			String FileSeparator = (String) System
					.getProperty("file.separator");
			classLocation = URLDecoder.decode(location.getFile().replace("/",
					FileSeparator), Charset.defaultCharset().name());
			classLocation = classLocation.substring(0, classLocation
					.lastIndexOf(FileSeparator) + 1);

		} catch (UnsupportedEncodingException e) {
			Logger.w("cant find main class dir");
		}
		return classLocation;
	}

}